package com.fubowen.lepton.ui.container.children.visited

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SortedList
import com.fubowen.lepton.R
import com.fubowen.lepton.bean.BookmarkBean
import com.fubowen.lepton.bean.Setting
import com.fubowen.lepton.bean.VisitedBean
import com.fubowen.lepton.conf.SiteConfigViewModel
import com.fubowen.lepton.databinding.FragmentVisitedBinding
import com.fubowen.lepton.databinding.FragmentVisitedContextMenuBinding
import com.fubowen.lepton.databinding.FragmentVisitedRemoveTimerBinding
import com.fubowen.lepton.extension.DAY_MS
import com.fubowen.lepton.extension.HOUR_MS
import com.fubowen.lepton.extension.MINUTE_MS
import com.fubowen.lepton.extension.filter
import com.fubowen.lepton.extension.forEach
import com.fubowen.lepton.helper.DBHelper
import com.fubowen.lepton.helper.IntentHelper.shareSite
import com.fubowen.lepton.helper.ViewHelper.confirm
import com.fubowen.lepton.helper.ViewHelper.findViewsByTag
import com.fubowen.lepton.helper.ViewHelper.setIcon
import com.fubowen.lepton.helper.ViewHelper.setVisible
import com.fubowen.lepton.helper.ViewHelper.toast
import com.fubowen.lepton.helper.ViewHelper.writeTextToClipboard
import com.fubowen.lepton.ui.container.ManagerFragmentDirections
import com.fubowen.lepton.ui.container.children.visited.recycler.OnItemClickListener
import com.fubowen.lepton.ui.container.children.visited.recycler.VisitedAdapter
import com.fubowen.lepton.ui.container.children.visited.recycler.VisitedSortedListAdapterCallback
import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.Timer
import java.util.TimerTask
import kotlin.math.ceil

class VisitedFragment : Fragment() {

    private lateinit var binding: FragmentVisitedBinding
    private val viewModel: SiteConfigViewModel by activityViewModels()
    private lateinit var layoutManager: LinearLayoutManager
    private lateinit var sortedList: SortedList<VisitedBean>
    private lateinit var adapter: VisitedAdapter
    private var activated: View? = null
    private val deleteIds = HashSet<Int>()

    private var timeToLive: Long? = null
    private var timer: Timer? = null

    private var isCheckAll: Boolean = false
    private var selectable: Boolean = false


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentVisitedBinding.inflate(inflater, container, false)
        adapter = VisitedAdapter(deleteIds, itemClickListener())
        sortedList = SortedList(VisitedBean::class.java, VisitedSortedListAdapterCallback(adapter))
        adapter.setDataSource(sortedList)
        layoutManager = binding.visitedRecycler.layoutManager as LinearLayoutManager
        binding.visitedRecycler.adapter = adapter
        binding.visitedRecycler.itemAnimator = null
        CoroutineScope(Dispatchers.Main).launch {
           DBHelper.db.visitedDao().all().collect { value ->
                sortedList.replaceAll(value)
                setBottomMenuState()
            }
        }
        initBottomMenuListener()
        initTimer()
        return binding.root
    }

    private fun itemClickListener() = object : OnItemClickListener {

        override fun onClick(view: View) {
            val position = layoutManager.getPosition(view)
            val item = sortedList.get(position)
            val action =
                ManagerFragmentDirections.actionManagerFragmentToSearchListItemDetailFragment(
                    searchText = item.title,
                    url = item.url!!
                )
            findNavController().navigate(action)
        }

        override fun onRemoveClick(view: View) {
            val position = layoutManager.getPosition(view)
            val item = sortedList.get(position)
            deleteIds.add(item.id)
            sortedList.updateItemAt(position, item)
        }

        override fun onRemoveOkClick(itemView: View) {
            val position = layoutManager.getPosition(itemView)
            val item = sortedList.get(position)
            CoroutineScope(Dispatchers.IO).launch {
                DBHelper.db.visitedDao().del(item)
                deleteIds.remove(item.id)
            }

            sortedList.updateItemAt(position, item)
        }

        override fun onRemoveCancelClick(itemView: View) {
            val position = layoutManager.getPosition(itemView)
            val item = sortedList.get(position)
            deleteIds.remove(item.id)
            sortedList.updateItemAt(position, item)
        }

        override fun onMoreMenuClick(itemView: View) {
            activated = itemView
            bottomPopupWindow.value.show()
        }
    }

    private fun initBottomMenuListener() {
        binding.visitedClearAll.setOnClickListener {
            requireContext().confirm(R.string.delete_tip, sortedList.size()) {
                CoroutineScope(Dispatchers.IO).launch {
                    DBHelper.db.visitedDao().clear()
                    setBottomMenuState()
                }
            }
        }
        binding.visitedTip.setOnClickListener { removeTimer.value.show() }
        binding.visitedEdit.setOnClickListener {
            selectable = !selectable
            if (selectable) {
                sortedList.forEach { it.selectable = selectable }
                binding.visitedClearAll.setVisible(false)
                binding.visitedDelete.setVisible(true)
            } else {
                sortedList.forEach {
                    it.selectable = selectable
                    it.isSelected = false
                }
                isCheckAll = false
                binding.visitedClearAll.setVisible(true)
                binding.visitedDelete.setVisible(false)
            }
        }
        binding.visitedDelete.setOnClickListener {
            CoroutineScope(Dispatchers.IO).launch {
                val ids = sortedList.filter { it.isSelected }.map { it.id }
                requireContext().confirm(R.string.delete_tip, ids.size) {
                    DBHelper.db.visitedDao().del(ids)
                    setBottomMenuState()
                }
            }
        }
    }

    private fun setBottomMenuState() {
        if (sortedList.size() == 0) {
            binding.visitedClearAll.isEnabled = false
            binding.visitedEdit.isEnabled = false
        } else {
            binding.visitedClearAll.isEnabled = true
            binding.visitedEdit.isEnabled = true
        }
    }

    private fun getItem(view: View): VisitedBean {
        val position = layoutManager.getPosition(view)
        return sortedList.get(position)
    }

    private fun bottomPopupWindowClickHandler(id: Int, itemView: View) {
        val item = getItem(itemView)
        when (id) {

            R.id.context_menu_delete -> {
                CoroutineScope(Dispatchers.IO).launch { DBHelper.db.visitedDao().del(item) }
            }

            R.id.context_menu_copy -> {
                context?.writeTextToClipboard(item.title, item.url)
                binding.root.toast(R.string.copy_tip, 3000)
            }

            R.id.context_menu_share -> {
                bottomPopupWindow.value.hide()
                val that = this
                CoroutineScope(Dispatchers.Main).launch {
                    that.shareSite(item.title, item.url)
                }
            }

            R.id.context_menu_open_window -> {
                val action =
                    ManagerFragmentDirections.actionManagerFragmentToSearchListItemDetailFragment(
                        searchText = item.title,
                        url = item.url ?: "",
                    )
                findNavController().navigate(action)
            }

            R.id.context_menu_add_bookmark -> {
                CoroutineScope(Dispatchers.IO).launch {
                    DBHelper.db.bookmarkDao().setOrIgnore(
                        BookmarkBean(
                            title = item.title,
                            url = item.url,
                            host = item.host,
                            icon = item.icon,
                            iconSource = item.iconSource
                        )
                    )
                }
                binding.root.toast(R.string.bookmark_home_tip, 3000)
            }
        }
    }

    private val bottomPopupWindow = lazy {
        BottomSheetDialog(requireContext()).apply {
            val binding = FragmentVisitedContextMenuBinding.inflate(layoutInflater)
            val viewList = binding.root.findViewsByTag("button")
            if (viewList.isNotEmpty()) {
                for (view in viewList) {
                    view.setOnClickListener {
                        activated?.let { view ->
                            bottomPopupWindowClickHandler(it.id, view)
                            this.hide()
                        }
                    }
                }
            }
            setOnShowListener {
                val item = getItem(activated!!)
                binding.contextMenuTitle.text = item.title
                binding.contextMenuIcon.setIcon(item.icon, item.iconSource)
                binding.contextMenuUrl.text = item.host
            }
            this.setContentView(binding.root)
        }
    }

    private fun removeTimerHandler(view: View) {
        val time = when (view.id) {
            R.id.timer_forever -> -1
            R.id.timer_hour_1 -> 60 * 60 * 1000
            R.id.timer_day_1 -> 1 * 24 * 60 * 60 * 1000L
            R.id.timer_week -> 7 * 24 * 60 * 60 * 1000L
            R.id.timer_month -> 30 * 24 * 60 * 60 * 1000L
            R.id.timer_year -> 365 * 24 * 60 * 60 * 1000L
            R.id.timer_none -> 0
            else -> -1
        }
        CoroutineScope(Dispatchers.IO).launch {
            DBHelper.db.settingDao().apply {
                setOrPut(Setting(key = VisitedBean.TTL, value = time.toString()))
            }
        }
    }

    private val removeTimer = lazy {
        BottomSheetDialog(requireContext()).apply {
            val binding = FragmentVisitedRemoveTimerBinding.inflate(layoutInflater)
            val viewList = binding.root.findViewsByTag("button")
            if (viewList.isNotEmpty()) {
                for (view in viewList) {
                    view.setOnClickListener {
                        removeTimerHandler(it)
                        hide()
                    }
                }
            }
            this.setContentView(binding.root)
        }
    }

    private fun formatTime(diff: Long): String {
        return when {
            diff > DAY_MS -> "${ceil(diff / DAY_MS).toInt()} 天"
            diff > HOUR_MS -> "${ceil(diff / HOUR_MS).toInt()} 小时"
            else -> "${ceil(diff / MINUTE_MS).toInt()} 分钟"
        }
    }

    private fun timerRun(ttl: Long) {
        val diff = System.currentTimeMillis() - ttl
        DBHelper.db.visitedDao().apply {
            del(diff)
            val minItem = minOfCreateTime()
            binding.visitedTip.apply {
                post {
                    if (minItem == null) {
                        text = "定时器"
                        return@post
                    }
                    val offset = ttl - (System.currentTimeMillis() - minItem.timestamp)
                    text = formatTime(offset)
                }
            }
        }
    }

    private fun setTimer() {
        timer?.cancel()
        timer?.purge()
        timeToLive?.let {
            if (it == -1L || it == 0L) {
                binding.visitedTip.apply {
                    post {
                        text = if (it == -1L) "定时器" else "关闭后清理"
                    }
                }
                return@let
            }
            timer = Timer().apply {
                schedule(object : TimerTask() {
                    override fun run() = timerRun(it)
                }, 0L, 5000)
            }
        }
    }

    private fun initTimer() {
        CoroutineScope(Dispatchers.IO).launch {
            DBHelper.db.settingDao().getFlow(VisitedBean.TTL).collect {
                timeToLive = it?.toLong()
                setTimer()
            }
        }
    }
}